<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html lang="zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta http-equiv="Content-Language" content="zh-CN"><link href="stylesheet.css" media="all" rel="stylesheet" type="text/css">
<title>认证方法</title>
<script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?d286c55b63a3c54a1e43d10d4c203e75"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script>
</head><body class="SECT1">
<div>
<table summary="Header navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><th colspan="5" align="center" valign="bottom">PostgreSQL 8.2.3 中文文档</th></tr>
<tr><td width="10%" align="left" valign="top"><a href="auth-pg-hba-conf.html" accesskey="P">后退</a></td><td width="10%" align="left" valign="top"><a href="client-authentication.html">快退</a></td><td width="60%" align="center" valign="bottom">章20. 用户认证</td><td width="10%" align="right" valign="top"><a href="client-authentication.html">快进</a></td><td width="10%" align="right" valign="top"><a href="client-authentication-problems.html" accesskey="N">前进</a></td></tr>
</table>
<hr align="LEFT" width="100%"></div>
<div class="SECT1"><h1 class="SECT1"><a name="AUTH-METHODS">20.2. 认证方法</a></h1>
<p>下面的小节更详细地描述认证方法。</p>
<div class="SECT2"><h2 class="SECT2"><a name="AUTH-TRUST">20.2.1. 信任认证</a></h2>
<p>如果声明了 <tt class="LITERAL">trust</tt> 认证模式，PostgreSQL 就假设任何可以连接到服务器的人都可以以任何他声明的数据库用户名(包括超级用户)连接。当然，在 <tt class="LITERAL">database</tt> 和 <tt class="LITERAL">user</tt> 字段里面的限制仍然适用。这个方法应该用于那些在连接到服务器已经有足够操作系统层次保护的环境里。</p>
<p><tt class="LITERAL">trust</tt> 认证对于单用户工作站的本地连接是非常合适和方便的。通常它本身并<span class="emphasis"><i class="EMPHASIS">不</i></span>适用于多用户环境的机器。不过，即使在多用户的机器上，你也可以使用 <tt class="LITERAL">trust</tt> ，只要你利用文件系统权限限制了对服务器的 Unix 域套接字文件的访问。要做这些限制，你可以设置 <tt class="VARNAME">unix_socket_permissions</tt> 参数(以及可能还有 <tt class="VARNAME">unix_socket_group</tt>)，就像<a href="runtime-config-connection.html">节17.3</a>里描述的那样。或者你可以设置 <tt class="VARNAME">unix_socket_directory</tt> ，把 Unix 域套接字文件放在一个经过恰当限制的目录里。</p>
<p>设置文件系统权限只能帮助 Unix 套接字连接，它不会限制本地 TCP/IP 连接。因此，如果你想利用文件系统权限来控制本地安全，那么删除 <tt class="FILENAME">pg_hba.conf</tt> 文件中的 <tt class="LITERAL">host ... 127.0.0.1 ...</tt> 行，或者把它改为一个非 <tt class="LITERAL">trust</tt> 的认证方法。</p>
<p><tt class="LITERAL">trust</tt> 认证模式只适合 TCP/IP 连接，只有在你信任那些 <tt class="LITERAL">trust</tt> 行上所有机器中的所有用户的时候才是合适的。很少有理由使用 <tt class="LITERAL">trust</tt> 作为任何除来自 <span class="SYSTEMITEM">localhost</span>(127.0.0.1) 以外的 TCP/IP 连接的认证方式。</p>
</div>
<div class="SECT2"><h2 class="SECT2"><a name="AUTH-PASSWORD">20.2.2. 口令认证</a></h2><a name="AEN23310"></a><a name="AEN23312"></a><a name="AEN23314"></a>
<p>以口令为基础的认证方法包括 <tt class="LITERAL">md5</tt>, <tt class="LITERAL">crypt</tt>, <tt class="LITERAL">password</tt> 。这些方法操作上非常类似，只不过口令通过连接传送的方法不同：MD5 散列、crypt 加密、明文。一个限制是 <tt class="LITERAL">crypt</tt> 不能使用存储在 <tt class="STRUCTNAME">pg_authid</tt> 中已加密的口令。</p>
<p>如果你担心口令被窃听，那么 <tt class="LITERAL">md5</tt> 比较合适，只有在你必需支持 7.2 以前的老的客户端的时候，才需要选 <tt class="LITERAL">crypt</tt> 。如果我们在开放的互联网上使用，应该尽可能避免使用 <tt class="LITERAL">password</tt>(除非你在连接上使用了 SSL/SSH 或其它通讯安全的连接封装)。</p>
<p>PostgreSQL 数据库口令与任何操作系统用户口令无关。各个数据库用户的口令是存储在 <tt class="LITERAL">pg_authid</tt> 系统表里面。口令可以用 SQL 语言命令 <a href="sql-createuser.html"><i>CREATE USER</i></a> 和 <a href="sql-alteruser.html"><i>ALTER USER</i></a> 等管理(比如 <kbd class="USERINPUT">CREATE USER foo WITH PASSWORD 'secret';</kbd> 。缺省时，如果没有明确设置口令，那么存储的口令是空并且该用户的口令认证总会失败。</p>
</div>
<div class="SECT2"><h2 class="SECT2"><a name="KERBEROS-AUTH">20.2.3. Kerberos 认证</a></h2><a name="AEN23338"></a>
<p>Kerberos 是一种适用于在公共网络上进行分布计算的工业标准的安全认证系统。对 Kerberos 系统的叙述远远超出了本文档的范围；总的说来它是相当复杂(同样也相当强大)的系统。<a href="http://www.nrl.navy.mil/CCS/people/kenh/kerberos-faq.html" target="_top">Kerberos FAQ</a> 或 <a href="http://web.mit.edu/kerberos/www/" target="_top">MIT Kerberos page</a> 是个开始学习的好地方。现存在好几种 Kerberos 发布的源代码。Kerberos 只提供安全认证，但并不加密在网络上传输的查询和数据，SSL 可以用于这个目的。</p>
<p>PostgreSQL 支持 Kerberos 5 ，Kerberos 支持必须在编译的时候打开。参阅<a href="installation.html">章14</a>获取更多信息。</p>
<p>PostgreSQL 运行时像一个普通的 Kerberos 服务。服务主的名字是 <tt class="LITERAL"><tt class="REPLACEABLE"><i>servicename</i></tt>/<tt class="REPLACEABLE"><i>hostname</i></tt>@<tt class="REPLACEABLE"><i>realm</i></tt></tt> 。</p>
<p><tt class="REPLACEABLE"><i>servicename</i></tt> 可以用 <a href="runtime-config-connection.html#GUC-KRB-SRVNAME">krb_srvname</a> 配置参数在服务器端设置，或者在客户端使用 <tt class="LITERAL">krbsrvname</tt> 连接参数设置(又见<a href="http://www.jinbuguo.com/postgresql/manual/libpq-connect.html">节29.1</a>)。编译的时候，可以把安装时的缺省 <tt class="LITERAL">postgres</tt> 修改掉，方法是使用 <tt class="LITERAL">./configure --with-krb-srvnam=whatever</tt> 。在大多数情况下，我们不需要修改这个参数。但是，如果需要在同一台主机上同时安装多套 PostgreSQL ，那么这个就是必须的了。有些 Kerberos 实现还可能要求其它的服务名，比如 Microsoft Active Directory 就要求服务名必须是大写的(<tt class="LITERAL">POSTGRES</tt>)。</p>
<p><tt class="REPLACEABLE"><i>hostname</i></tt> 是服务器的全限定主机名。服务主的领域就是主机的首选领域。</p>
<p>客户主自己必须用它们自己的 PostgreSQL 用户名作为第一个部件，比如 <tt class="LITERAL">pgusername/otherstuff@realm</tt>  。目前 PostgreSQL 没有检查客户的域；因此如果你打开了跨域的认证，那么在任意域里任何可以和你通讯的主都会被接受。</p>
<p>确认服务器的密钥表文件是可以被 PostgreSQL 服务器帐户读取(最好就是只读的)(又见<a href="postgres-user.html">节16.1</a>)密钥文件(keytab)的位置是用配置参数 <a href="runtime-config-connection.html#GUC-KRB-SERVER-KEYFILE">krb_server_keyfile</a> 声明的。缺省是 <tt class="FILENAME">/usr/local/pgsql/etc/krb5.keytab</tt>(或者任何在编译的时候声明为 <tt class="VARNAME">sysconfdir</tt> 的目录)。</p>
<p>密钥表文件(keytab)是在 Kerberos 软件里生成的，参阅 Kerberos 文档获取细节。下面的例子是可以用于 MIT 兼容的 Kerberos 5 实现：</p>
<pre class="SCREEN"><samp class="PROMPT">kadmin% </samp><kbd class="USERINPUT">ank -randkey postgres/server.my.domain.org</kbd>
<samp class="PROMPT">kadmin% </samp><kbd class="USERINPUT">ktadd -k krb5.keytab postgres/server.my.domain.org</kbd></pre>
<p>在和数据库连接的时候，请确保自己对每个主都拥有一张匹配所请求的数据库用户名的门票。比如，对于数据库用户 <tt class="LITERAL">fred</tt> ，主 <tt class="LITERAL">fred@EXAMPLE.COM</tt> 和 <tt class="LITERAL">fred/users.example.com@EXAMPLE.COM</tt> 都可以用于与数据库服务器认证。</p>
<p>如果你在 Apache 服务器上使用了 <a href="http://modauthkerb.sf.net" target="_top"><span class="APPLICATION">mod_auth_kerb</span></a> 和 <span class="APPLICATION">mod_perl</span> 模块，你可以用一个 <span class="APPLICATION">mod_perl</span> 脚本进行 <tt class="LITERAL">AuthType KerberosV5SaveCredentials</tt> 。这样就有了一个通过 web 的安全数据库访问，不需要额外的口令。</p>
</div>
<div class="SECT2"><h2 class="SECT2"><a name="AUTH-IDENT">20.2.4. 基于 Ident 的认证</a></h2><a name="AEN23399"></a>
<p>ident 认证方法是通过获取客户端的操作系统用户名，然后使用一个记录了系统用户与数据库用户对应关系的映射文件，判断对应许可的数据库用户名的方法来认证。判断客户端的用户名是非常关键的安全点，根据连接类型的不同，它的实现方法也略有不同。</p>
<div class="SECT3"><h3 class="SECT3"><a name="AEN23402">20.2.4.1. 透过 TCP/IP 的身份认证</a></h3>
<p>"Identification Protocol"(标识协议)在 <i class="CITETITLE">RFC 1413</i> 里面描述。实际上每个类 Unix 的操作系统都带着一个缺省时侦听 113 端口的身份服务器。身份服务器的基本功能是回答类似这样的问题： <span class="QUOTE">"是什么用户从你的端口 <tt class="REPLACEABLE"><i>X</i></tt> 初始化出来连接到我的端口 <tt class="REPLACEABLE"><i>Y</i></tt> 上来了?"</span> 。因为在建立起物理连接后，PostgreSQL 既知道 <tt class="REPLACEABLE"><i>X</i></tt> 也知道 <tt class="REPLACEABLE"><i>Y</i></tt> ，因此它可以询问运行尝试连接的客户端的主机，并且理论上可以用这个方法判断发起连接的操作系统用户。</p>
<p>这样做的缺点是它取决于客户端的完整性：如果客户端不可信或者被攻击者攻破，而且它们可以在 113 端口上运行任何程序并且返回他们选择的任何用户的话，就无法认证了。因此这个认证方法只适用于封闭的网络，这样的网络里的每台客户机都处于严密的控制下并且数据库和操作系统管理员可以比较方便地联系上。换句话说，你必须信任运行身份(ident)服务的机器。下面是警告：<a name="AEN23414"></a>
<table border="0" width="100%" cellspacing="0" cellpadding="0" class="BLOCKQUOTE">
<tr><td width="10%" valign="TOP">&nbsp;</td><td valign="TOP"><p>身份标识协议并不适用于认证或者访问控制协议。</p></td><td width="10%" valign="TOP">&nbsp;</td></tr>
<tr><td colspan="2" align="RIGHT" valign="TOP">--RFC 1413</td><td width="10%">&nbsp;</td></tr>
</table></P>
<p>有些身份服务器有一个非标准的选项，导致返回的用户名是加密的，使用的是只有原机器的管理员知道的一个密钥。在与 PostgreSQL 配合使用身份认证的时候，你<span class="emphasis"><i class="EMPHASIS">一定不能</i></span>使用这个选项，因为 PostgreSQL 没有任何方法对返回的字符串进行解密以获取实际的用户名。</p>
</div>
<div class="SECT3"><h3 class="SECT3"><a name="AEN23421">20.2.4.2. 透过本地套接字的身份认证</a></h3>
<p>在支持用于 Unix 域套接字的 <tt class="SYMBOL">SO_PEERCRED</tt> 请求的系统上(<span class="SYSTEMITEM">Linux</span>, <span class="SYSTEMITEM">FreeBSD</span>, <span class="SYSTEMITEM">NetBSD</span>, <span class="SYSTEMITEM">OpenBSD</span>, <span class="SYSTEMITEM">BSD/OS</span>)，身份认证也可以用于局部连接。这个时候，使用身份认证不会增加安全风险；实际上这也是在这种系统上使用本地连接时的首选方法。</p>
<p>在没有 <tt class="SYMBOL">SO_PEERCRED</tt> 求的系统上，身份认证只能通过 TCP/IP 连接获取。如果需要绕开这个限制，我们可以声明 <span class="SYSTEMITEM">localhost</span> 地址 <span class="SYSTEMITEM">127.0.0.1</span> ，然后让连接指向这个地址。这个方法适用于你信任本机身份认证服务器的场合。</p>
</div>
<div class="SECT3"><h3 class="SECT3"><a name="AUTH-IDENT-MAPS">20.2.4.3. Ident 映射</a></h3>
<p>当使用以身份为基础的认证时，在判断了初始化连接的操作系统用户名后，PostgreSQL 判断他是否可以以他所请求的数据库用户的身份连接。这个判断是由跟在 <tt class="FILENAME">pg_hba.conf</tt> 文件里的 <tt class="LITERAL">ident</tt> 关键字后面的身份映射控制的。有一个预定义的身份映射是 <tt class="LITERAL">sameuser</tt> ，表示任何操作系统用户都可以以同名数据库用户进行连接(如果后者存在的话)。其它映射必须手工创建。</p>
<p>非 <tt class="LITERAL">sameuser</tt> 的身份映射定义在身份映射文件(缺省名 <tt class="FILENAME">pg_ident.conf</tt>)里，并且缺省存放在集群的数据目录里。不过，我们也可以把映射文件放在其它地方，参阅 <a href="runtime-config-file-locations.html#GUC-IDENT-FILE">ident_file</a> 配置参数。身份映射文件包含下面通用的格式：</p>
<pre class="SYNOPSIS"><tt class="REPLACEABLE"><i>map-name</i></tt> <tt class="REPLACEABLE"><i>ident-username</i></tt> <tt class="REPLACEABLE"><i>database-username</i></tt></pre>
<p>注释和空白与 <tt class="FILENAME">pg_hba.conf</tt> 文件里的一样处理。<tt class="REPLACEABLE"><i>map-name</i></tt> 是将用于在 <tt class="FILENAME">pg_hba.conf</tt> 里引用这个映射的任意名称。另外两个域声明某个操作系统用户被允许以哪个数据库用户的身份进行连接。同一个 <tt class="REPLACEABLE"><i>map-name</i></tt> 可以重复用于在一个映射里声明更多的用户映射。对一个操作系统用户可以映射为多少个数据库用户没有限制，反之亦然。</p>
<p>在系统启动和主服务器收到一个 <span class="SYSTEMITEM">SIGHUP</span> 信号的时候会读取 <tt class="FILENAME">pg_ident.conf</tt> 文件。如果你在一台活跃的系统上编辑该文件，那么你需要给主服务器发信号(使用 <tt class="LITERAL">pg_ctl reload</tt> 或 <tt class="LITERAL">kill -HUP</tt>)令其重新读取该文件。</p>
<p><a href="auth-pg-hba-conf.html#EXAMPLE-PG-HBA.CONF">例20-1</a>里是一个可以和在<a href="auth-methods.html#EXAMPLE-PG-IDENT.CONF">例20-2</a>里面演示的 <tt class="FILENAME">pg_ident.conf</tt> 文件配合使用的 <tt class="FILENAME">pg_hba.conf</tt> 文件。在这个例子的设置里，任何登录到 192.168 网络里的机器的用户，如果用户名不是 <tt class="LITERAL">bryanh</tt>, <tt class="LITERAL">ann</tt>, <tt class="LITERAL">robert</tt> 就不能获准访问。Unix 用户 <tt class="LITERAL">robert</tt> 只有在试图以 PostgreSQL 用户 <tt class="LITERAL">bob</tt> 身份连接时才允许访问，而不能是 <tt class="LITERAL">robert</tt> 或其它什么身份。<tt class="LITERAL">ann</tt> 将只允许以 <tt class="LITERAL">ann</tt> 的身份连接。用户 <tt class="LITERAL">bryanh</tt> 允许以他自己的 <tt class="LITERAL">bryanh</tt> 身份或者作为 <tt class="LITERAL">guest1</tt> 进行连接。</p>
<div class="EXAMPLE"><a name="EXAMPLE-PG-IDENT.CONF"></a>
<p><b>例20-2. 一个 <tt class="FILENAME">pg_ident.conf</tt> 文件例子</b></p>
<pre class="PROGRAMLISTING"># MAPNAME     IDENT-USERNAME    PG-USERNAME

omicron       bryanh            bryanh
omicron       ann               ann
# bob 在这台机器上的用户名是 robert
omicron       robert            bob
# 也可以以 guest1 身份连接
omicron       bryanh            guest1</pre>
</div>
</div>
</div>
<div class="SECT2"><h2 class="SECT2"><a name="AUTH-LDAP">20.2.5. LDAP 认证</a></h2><a name="AEN23485"></a>
<p>这个认证方法操作起来类似 <tt class="LITERAL">password</tt> ，只不过它使用 LDAP 作为认证机制。LDAP 只用于验证用户名/口令对。因此，在使用 LDAP 进行认证之前，用户必须已经存在于数据库里。你可以在 <tt class="FILENAME">pg_hba.conf</tt> 文件的 <tt class="LITERAL">ldap</tt> 关键字后面提供自己的可选服务名。该参数的格式如下：</p>
<pre class="SYNOPSIS">ldap[<tt class="REPLACEABLE"><i>s</i></tt>]://<tt class="REPLACEABLE"><i>servername</i></tt>[:<tt class="REPLACEABLE"><i>port</i></tt>]/<tt class="REPLACEABLE"><i>base dn</i></tt>[;<tt class="REPLACEABLE"><i>prefix</i></tt>[;<tt class="REPLACEABLE"><i>suffix</i></tt>]]
    </pre>
<p>例如：</p>
<pre class="SYNOPSIS">ldap://ldap.example.net/dc=example,dc=net;EXAMPLE\
    </pre>
<p>如果指定了 <tt class="LITERAL">ldaps</tt> 而不是 <tt class="LITERAL">ldap</tt> ，那么将使用 TLS 加密连接。需要注意的是这仅仅加密 PostgreSQL 服务器与 LDAP 服务器之间的连接。客户端与 PostgreSQL 服务器之间并不受此影响。要使用 TLS 加密，你需要在配置 PostgreSQL 之前先配置好 LDAP 库。加密 LDAP 仅在平台的 LDAP 库支持的情况下才可用。</p>
<p>如果没有指定端口，将使用 LDAP 库默认的端口。</p>
<p>服务器将使用客户端提供的用户名绑定到 <tt class="REPLACEABLE"><i>base dn</i></tt> 指定的识别名(Distinguished Name)上。如果指定了 <tt class="REPLACEABLE"><i>prefix</i></tt> 和 <tt class="REPLACEABLE"><i>suffix</i></tt> ，那么将在邦定之前被前缀/后缀到用户名上。通常前缀参数用于在活动目录环境中指定 <tt class="REPLACEABLE"><i>cn=</i></tt>, <tt class="REPLACEABLE"><i>DOMAIN\</i></tt> 。</p>
</div>
<div class="SECT2"><h2 class="SECT2"><a name="AUTH-PAM">20.2.6. PAM 认证</a></h2><a name="AEN23511"></a>
<p>这个认证方法操作起来类似 <tt class="LITERAL">password</tt> ，只不过它使用 PAM 作为认证机制。缺省的 PAM 服务名是 <tt class="LITERAL">postgresql</tt> 。你可以在 <tt class="FILENAME">pg_hba.conf</tt> 文件的 <tt class="LITERAL">pam</tt> 关键字后面提供自己的可选服务名。PAM 只用于验证用户名/口令对。因此，在使用 PAM 进行认证之前，用户必须已经存在于数据库里。有关 PAM 的更多信息，请阅读 <a href="http://www.kernel.org/pub/linux/libs/pam/" target="_top">Linux-PAM 页面</a> 和 <a href="http://www.sun.com/software/solaris/pam/" target="_top"><span class="SYSTEMITEM">Solaris</span> PAM 页面</a>。</p>
</div>
</div>
<div>
<hr align="LEFT" width="100%">
<table summary="Footer navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><td width="33%" align="left" valign="top"><a href="auth-pg-hba-conf.html" accesskey="P">后退</a></td><td width="34%" align="center" valign="top"><a href="index.html" accesskey="H">首页</a></td><td width="33%" align="right" valign="top"><a href="client-authentication-problems.html" accesskey="N">前进</a></td></tr>
<tr><td width="33%" align="left" valign="top"><tt class="FILENAME">pg_hba.conf</tt> 文件</td><td width="34%" align="center" valign="top"><a href="client-authentication.html" accesskey="U">上一级</a></td><td width="33%" align="right" valign="top">用户认证</td></tr>
</table>
</div>
</body></html>